package MySQL::Query::IndexesOrder;

use strict;
use warnings;
use Carp;
use Data::Dumper;
use Algorithm::Combinatorics qw( variations );

use base qw(MySQL::Query::Base);
__PACKAGE__->mk_accessors(qw( ));


sub indexes_comb {
      my ($self , $indexes , $tables_o) = @_;
      
      my @res = ();
      my @keys = keys %$indexes;
      
      return unless $#keys; 
      
      my $tables = $tables_o->tables;
      my $first_table_indexes = $indexes->{$tables->[0]};
      
      my $tables_offset = $self->tables_offset($indexes , $tables , 1);
      my $tables_keys_list = $self->tables_keys_list($indexes , $tables , 1);
      
      my $final_var;
      if ($#{$tables_keys_list}) {
            my @variations = variations($tables_keys_list , $#keys);
            $final_var = $self->apply_verif(\@variations , $indexes , $tables ,  $tables_offset , $first_table_indexes);
      } else {
            foreach (@$first_table_indexes) {
                  my @temp = ();
                  push @temp , $_;
                  push @temp , $tables_keys_list->[0];
                  push @$final_var , \@temp;
            }
      }
      
      return $self->create_hash_st($final_var , $indexes);
}

sub create_hash_st {
      my ($self , $var , $indexes) = @_;
      
      my @res = ();
      foreach my $v (@$var) {
            $self->{_get_key} = []; #handles PRIMARY bugfix
            my @temp = ();
            foreach (@$v) {
                  push @temp , { $self->get_key($indexes , $_) => $_ }
            }
            push @res , \@temp;
      }
      return \@res;
}

sub get_key {
      my ($self , $indexes , $value) = @_;
      
      T: foreach my $table (keys %$indexes) {
            foreach my $key (@{$indexes->{$table}}) {
                  if ($key eq $value) {
                        return $table unless $key eq 'PRIMARY';
                        
                        #PRIMARY bugfix
                        if (grep { $_ eq $table } @{$self->{_get_key}}) {
                              next T;
                        } else {
                              push @{$self->{_get_key}} , $table;
                              return $table;
                        }
                  }
            }
      }
}

sub tables_keys_list {
      my ($self , $indexes , $tables , $offset) = @_;
      
      my @values = ();
      foreach ( $offset .. $#{$tables} ) {
            push @values , @{$indexes->{$tables->[$_]}};
      }
      
      return \@values;
}

sub tables_offset {
      my ($self , $indexes , $tables , $offset) = @_;
      
      my @values = ();
      foreach ( $offset .. $#{$tables} ) {
            push @values , $indexes->{$tables->[$_]};
      }
      
      return \@values;
}

sub apply_verif {
      my ($self , $variations , $indexes , $tables , $tables_offset , $first_table_indexes) = @_;
      
      my $verif_seq        = $self->verif_seq($variations , $tables_offset);
      
      #print Dumper $verif_seq;
      
      my $with_added_first = $self->add_first_keys($verif_seq , $first_table_indexes);
      my $final_orders     = $self->apply_seq($with_added_first , $indexes , $tables);
      
      return $final_orders;
}

sub apply_seq {
      my ($self , $var , $indexes , $tables) = @_;
      
      my @res = ();
      foreach my $v (@$var) {
            my $okey = 1;
            for (my $i = 0; $i <= $#{$v}; $i++) {
                  my $possible_indexes = $indexes->{$tables->[$i]};
                  $okey = 0 unless (grep { $_ eq $v->[$i] } @$possible_indexes);
            }
            push @res , $v if ($okey);
      }
      return \@res;
}

sub add_first_keys {
      my ($self , $var , $fti) = @_;
      
      my @res = ();
      foreach my $ft (@$fti) {
            foreach my $v (@$var) {
                  my @f = reverse @$v;
                  push @f, $ft;
                  my @n = reverse @f;
                  push @res , \@n;
            }
      }
      return \@res;
}

sub verif_seq {
      my ($self , $var , $to) = @_;
          
      my @res = ();
      V: foreach my $v (@$var) {
            foreach my $s (@$to) {
                  push @res , $v unless $self->eql( $v , $s );
                  next V;
            }
      }
      return \@res;
}

sub eql {
      my ($self , $a , $b) = @_;
      
      return 0 if ($#{$a} ne $#{$b});

      my (%seen , @aonly);  
      @seen{@{$b}} = ();

      foreach my $item (@{$a}) {
            push(@aonly, $item) unless exists $seen{$item};
      }

      return 0 if (@aonly);
      return 1;
}

1;

=head1 NAME

MySQL::Query::IndexesOrder

=head1 SYNOPSIS
	
=head1 DESCRIPTION

=head1 METHODS

=head2 new()

=head2 order()

=head2 comp()
